package com.info.consumer;

import com.info.protocol.constants.CommonConstant;
import com.info.protocol.enums.MessageTypeEnum;
import com.info.protocol.enums.SerializeTypeEnum;
import com.info.protocol.netty.client.NettyClient;
import com.info.protocol.netty.core.*;
import io.netty.channel.DefaultEventLoop;
import io.netty.util.concurrent.DefaultPromise;
import io.netty.util.concurrent.Promise;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

@Slf4j
public class CustomInvocationHandler implements InvocationHandler {

    private final String serviceAddress;

    private final int servicePort;

    public CustomInvocationHandler(String serviceAddress, int servicePort) {
        this.serviceAddress = serviceAddress;
        this.servicePort = servicePort;
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log.info("begin invoke target server");
        //组装参数
        Protocol<Request> protocol = new Protocol<>();
        long requestId = RequestHolder.REQUEST_ID.incrementAndGet();
        // 魔数 16bit|协议版本 8bit|序列化方式 8bit| 消息长度 32bit |消息类型（请求还是响应）2bit|messageId 64bit
        Header header = new Header(CommonConstant.MAGIC, CommonConstant.PROTOCOL_VERSION,
                SerializeTypeEnum.JSON.getCode(), 0, MessageTypeEnum.REQUEST.getCode(), requestId);
        protocol.setHeader(header);
        Request request = new Request();
        request.setClassName(method.getDeclaringClass().getName());
        request.setMethodName(method.getName());
        request.setParameterTypes(method.getParameterTypes());
        request.setParams(args);
        protocol.setContent(request);
        //发送请求
        NettyClient nettyClient = new NettyClient(serviceAddress, servicePort);
        //构建异步数据处理
        CustomFuture<Response> future = new CustomFuture<>(new DefaultPromise<>(new DefaultEventLoop()));
        RequestHolder.REQUEST_MAP.put(requestId, future);
        nettyClient.sendRequest(protocol);
        final Promise<Response> promise = future.getPromise();
        final Response response = promise.get();
        final Object data = response.getData();
        return data;
    }
}
